package com.ludomancy.spaceopera;


import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.util.Vector;

import com.ludomancy.gamelib.ImageAnimation;
import com.ludomancy.gamelib.ImageManipulation;
import com.ludomancy.gamelib.ImageStrip;
import com.ludomancy.gamelib.ResourceManager;
import com.ludomancy.gamelib.entity.EntityCollisionFilter;

public class Player extends BasicEntity
{
	public static final int PLAYER_SPEED = 60;
	private Point target = new Point();
	public boolean activated = false;
	private ImageStrip sprite;
	private ImageAnimation animation;
	private ImageAnimation spaceMan;
	private Image lander;
	private Point lastPosition;
	public BasicEntity interactableEntity = null;
	private int cargo;
	public int maxCargo = 300;
	public int shield;
	private boolean inventoryItemActivated = false;
	
	public InventoryItem inventory;
	
	public boolean landerShielded = false;
	
	// abilities
	public boolean hasTransilient = false;
	
	public Player(Point pos)
	{
		super(pos);
		z = ZTOP;
		sprite = new ImageStrip(ResourceManager.getImage("char.png"), 14, 11);
		lander = ResourceManager.getImage("lander.png");
		animation = new ImageAnimation(sprite,3);
		spaceMan = ImageAnimation.create("spaceman.png", 13, 14, 8);
		spaceMan.play();
		spaceMan.setSequenceBouncingLoop();
		spaceMan.looping = true;
		animation.play();
		animation.looping = true;
		lastPosition = pos;
		shield = getMaxShield();
		
		width = (int) proj.screenToWorldX(animation.strip.frameWidth);
		height = (int) proj.screenToWorldY(animation.strip.frameHeight);
	}
	
	public int[] getBitmask(int x, int y, int w, int h)
	{
		if(Game.game.currentWorld instanceof LandWorld)
		{
			return ImageManipulation.extractBitmask(lander, x, y, w, h);
		}
		else
		if(Game.game.currentWorld instanceof StationWorld)
		{
			return spaceMan.getBitmask(x, y, w, h);
		}
		else
		{
			return animation.getBitmask(x, y, w, h);
		}
	}
	
	public int getWidth()
	{
		if(Game.game.currentWorld instanceof LandWorld)
		{
			return (int) proj.screenToWorldX(lander.getWidth(null));
		}
		else
		if(Game.game.currentWorld instanceof StationWorld)
		{
			return (int) proj.screenToWorldX(spaceMan.strip.frameWidth);
		}
		return width;
	}
	
	public int getHeight()
	{
		if(Game.game.currentWorld instanceof LandWorld)
		{
			return (int) proj.screenToWorldY(lander.getHeight(null));
		}
		else
		if(Game.game.currentWorld instanceof StationWorld)
		{
			return (int) proj.screenToWorldY(spaceMan.strip.frameHeight);
		}
		return height;
	}
	
	
	public int getCargo()
	{
		return cargo;
	}
	
	public boolean hasCargoSpace()
	{
		return cargo < maxCargo;
	}
	
	public void addCargo(int weight)
	{
		cargo = Math.min(weight+cargo, maxCargo);
	}
	
	public void hit(int damage)
	{
		// shielded lander does not receive full damage
		if(Game.game.currentWorld instanceof LandWorld && landerShielded)
		{
			return;
		}
		shield -= damage;
		
		if(shield == 0)
		{
			// dead!
			die();
		}
		else
		{
			SpaceOperaApp.mainWidget.space.startShake();
		}
			
	}
	
	private void die()
	{
		// TODO: reset values, ask for paying back the lost ship
		Game.game.death();
	}
	
	public int getMaxShield()
	{
		return 100;
	}
	
	public int getShield()
	{
		return shield;
	}
		
	public void setTarget(Point target)
	{
		this.target.setLocation(target);
	}

	public void paint(Graphics g, int x, int y)
	{
		if(inventoryItemActivated)
		{
			inventory.paintPlayerUnderlay(g, x, y);
		}

		if(Game.game.currentWorld instanceof LandWorld)
		{
			if(landerShielded)
				g.drawImage(ResourceManager.getImage("bluelander.png"), x, y, null);
			else
				g.drawImage(lander, x, y, null);
		}
		else
		if(Game.game.currentWorld instanceof StationWorld)
		{
			spaceMan.update();
			spaceMan.paintCurrentFrame(g, x, y);
		}
		else
		{
			animation.update();
			animation.paintCurrentFrame(g, x, y);
		}
	}
	
	private Point snapToScreen()
	{
		int px = Math.min(Math.max(getWidth()/2, pos.x), parent.width-getWidth()/2);
		int py = Math.min(Math.max(getHeight()/2, pos.y), parent.height-getHeight()/2);
		return new Point(px,py);
	}
	
	public boolean update()
	{
		if(hasTransilient)
		{
			// teleport!
			pos.setLocation(target);
		}
		else
		{
			pos = getNextPos(target, PLAYER_SPEED);
		}
		pos = snapToScreen();
		
		if(lastPosition.equals(pos))
		{
			animation.looping = false;
		}
		else
		{
			animation.looping = true;
			animation.play();
			animation.rewind();
		}
		lastPosition.setLocation(pos);

		// collisions
		interactableEntity = null;
		Vector near = parent.getEntities(new EntityCollisionFilter(this, proj));
		for (int i = 0; i < near.size(); i++)
		{
			BasicEntity e = (BasicEntity) near.elementAt(i);
			if(e != this)
			{
				e.onPlayerHit(this);
				if(e.isInteractable() && !inventoryItemActivated)
				{
					interactableEntity = e;
					if(activated)
					{
						if(inventory != null)
						{
							if(inventory.interact(e))
							{
								break;
							}
						}
						e.onPlayerInteraction(this);
					}
					break;
				}
			}
		}
		if(inventory != null)
		{
			inventory.update();
			inventory.update(this, activated);
		}
		inventoryItemActivated = false;
		if(canActivateItem())
		{
			inventoryItemActivated = activated;
		}
		
		return false;
	}
	
	public String getInteractionVerb()
	{
		if(inventory != null)
		{
			return inventory.getInteractionVerbFor(interactableEntity);
		}
		return interactableEntity.getInteractionVerb();
	}
	
	public boolean canInteract()
	{
		return interactableEntity != null;
	}
	
	
	public boolean canActivateItem()
	{
		return inventory != null && !inventoryItemActivated && interactableEntity == null && inventory.canBeUsed();
	}
	
	public void onRemoval()
	{
		interactableEntity = null;
		activated = false;
	}
	
	public void onAdittion()
	{
		interactableEntity = null;
		activated = false;		
	}

	public void rechargeShields()
	{
		shield = getMaxShield();
	}

	public void pay(int cost)
	{
		cargo -= cost;
	}
}
